package cn.xju.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * JDBC 工具类，用于获取和关闭数据库连接。
 * 使用 Druid 连接池管理连接，并通过 ThreadLocal 保证线程安全。
 */
public class JDBCUtils {
    // 数据源对象，使用 Druid 实现
    private static DataSource dataSource = null;

    // 使用 ThreadLocal 为每个线程保存独立的 Connection 对象，实现事务控制
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    // 静态代码块：类加载时初始化数据源
    static {
        // 从类路径加载数据库配置文件 db.properties
        InputStream resourceAsStream = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        try {
            // 加载配置文件内容到 Properties 对象中
            properties.load(resourceAsStream);
            // 使用 Druid 创建数据源
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            // 初始化失败则抛出运行时异常
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取数据库连接，优先从当前线程中获取（保证事务一致性）。
     * 如果没有则从连接池中获取并绑定到当前线程。
     *
     * @return 数据库连接
     */
    public static Connection getConnection() {
        try {
            // 尝试从 ThreadLocal 中获取当前线程已绑定的连接
            Connection connection = threadLocal.get();
            if (connection == null) {
                // 如果没有，则从数据源中获取新连接
                connection = dataSource.getConnection();
                // 绑定到当前线程
                threadLocal.set(connection);
            }
            return connection;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭数据库连接。
     * 注意：此方法并未真正关闭连接，而是将其归还给连接池（如果使用连接池）。
     * 同时移除 ThreadLocal 中的连接引用，避免内存泄漏。
     *
     * @param conn 要关闭的连接
     */
    public static void close(Connection conn) {
        // 释放连接
        try {
            // 获取当前线程绑定的连接
            Connection connection = threadLocal.get();
            if (connection != null) {
                // 移除当前线程中的连接对象
                threadLocal.remove();
                // 恢复自动提交模式（防止影响下一次使用）
                connection.setAutoCommit(true);
                // 关闭连接（实际是归还给连接池）
                connection.close();
            }
            // 如果传入的连接不为空，也尝试关闭
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
